package com.winit.openapi.apiadapter.controller.util;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletRequest;

import net.sf.json.JSONArray;
import net.sf.json.JSONException;
import net.sf.json.JSONObject;
import net.sf.json.util.JSONUtils;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.winit.openapi.constants.ApiConstant;
import com.winit.openapi.constants.ErrorCode;
import com.winit.openapi.exception.ApiException;
import com.winit.openapi.model.RequestMsg;
import com.winit.openapi.util.MD5Util;
import com.winit.openapi.util.ParameterAdapterUtils;
import com.winit.openapi.util.SignUtil;

/**
 * 3E的RequestMsg生成类，3E的json解析使用的是net.sf.json.*下的包，而openAPI使用的是com.alibaba.
 * fastjson.*包
 * net.sf.json.*解析json默认不会对json的属性进行冲排序，而com.alibaba.fastjson会默认对解析的json进行属性排序
 * 导致的结果是在后续进行签名校验时候会出异常，报认证失败
 * 
 * @version <pre>
 * Author   Version     Date        Changes
 * minghao.deng     1.0         2016年12月12日     Created
 *
 * </pre>
 * @since 1.
 */
public class RequestMsg3EUtil {

    private static final Logger logger = LoggerFactory.getLogger(RequestMsg3EUtil.class);

    /**
     * 3E的sign生成加密字符串方法：data使用RequestMsg数据
     * 
     * @param requestMsg
     * @param token
     * @return
     */
    public static String buildJsonStrByRequestMsg(RequestMsg requestMsg, String token) {
        StringBuffer buf = new StringBuffer();
        buf.append(token);
        buf.append("action").append(requestMsg.getAction());
        buf.append("app_key").append(requestMsg.getApp_key());
        if (requestMsg.getData() != null && StringUtils.isNotBlank(requestMsg.getData().toString())) {
            buf.append("data").append(JSONObject.fromObject(requestMsg.getData()).toString());
        } else {
            buf.append("data").append("");
        }
        buf.append("format").append(requestMsg.getFormat() == null ? "" : requestMsg.getFormat());
        buf.append("platform").append(requestMsg.getPlatform() == null ? "" : requestMsg.getPlatform());
        buf.append("sign_method").append(requestMsg.getSign_method() == null ? "" : requestMsg.getSign_method());
        buf.append("timestamp").append(requestMsg.getTimestamp() == null ? "" : requestMsg.getTimestamp());
        buf.append("version").append(requestMsg.getVersion() == null ? "" : requestMsg.getVersion());
        buf.append(token);

        return buf.toString();
    }

    /**
     * 3E的sign生成加密字符串方法:data使用原始报文
     * 
     * @param requestMsg
     * @param token
     * @return
     */
    public static String buildJsonStrBySourceData(RequestMsg requestMsg, String sourceData, String token) {
        StringBuffer buf = new StringBuffer();
        buf.append(token);
        buf.append("action").append(requestMsg.getAction());
        buf.append("app_key").append(requestMsg.getApp_key());
        if (sourceData != null && StringUtils.isNotBlank(sourceData)) {
            buf.append("data").append(sourceData);
        } else {
            buf.append("data").append("");
        }
        buf.append("format").append(requestMsg.getFormat() == null ? "" : requestMsg.getFormat());
        buf.append("platform").append(requestMsg.getPlatform() == null ? "" : requestMsg.getPlatform());
        buf.append("sign_method").append(requestMsg.getSign_method() == null ? "" : requestMsg.getSign_method());
        buf.append("timestamp").append(requestMsg.getTimestamp() == null ? "" : requestMsg.getTimestamp());
        buf.append("version").append(requestMsg.getVersion() == null ? "" : requestMsg.getVersion());
        buf.append(token);

        return buf.toString();
    }

    /**
     * 参数处理
     * 
     * @param request
     * @param responseMsg
     * @return
     * @throws IOException
     */
    public static RequestMsg doPrepare(ServletRequest request) {

        JSONObject json = null;
        RequestMsg requestMsg = null;
        String inputJsonStr = null;
        String encoding = request.getCharacterEncoding();

        try {

            if (StringUtils.isBlank(encoding)) {
                encoding = ApiConstant.CHARSET_UTF8;
            }

            inputJsonStr = IOUtils.toString(request.getInputStream(), encoding);

            if (StringUtils.isBlank(inputJsonStr)) {
                // 如果InputStream为空，则去request中取，如果仍然为空，则抛出异常
                inputJsonStr = (String) request.getAttribute(ApiConstant.SOURCE_INPUT_STRING);
                if (StringUtils.isBlank(inputJsonStr)) {
                    throw new ApiException(ErrorCode.ILLEGAL_JSON_STRING);
                }
            }

            json = JSONObject.fromObject(inputJsonStr);

            if (json.containsKey("data")) {
                Map<String, Class<?>> clazzMap = new HashMap<String, Class<?>>();
                Object data = json.get("data");
                if (JSONUtils.isArray(data)) {
                    clazzMap.put("data", JSONArray.class);
                } else {
                    clazzMap.put("data", JSONObject.class);
                }
                requestMsg = (RequestMsg) JSONObject.toBean(json, RequestMsg.class, clazzMap);
            } else {
                requestMsg = (RequestMsg) JSONObject.toBean(json, RequestMsg.class);
            }
            // API 2.0入参参数适配 2016-08-09
            if (null != requestMsg && ApiConstant.API_VERSION_2.equals(requestMsg.getVersion())) {
                requestMsg = ParameterAdapterUtils.handleInputAdapte(requestMsg);
            }

        } catch (JSONException e) {
            logger.warn("illegal json string:" + inputJsonStr);
            throw new ApiException(ErrorCode.ILLEGAL_JSON_STRING);
        } catch (IOException e) {
            logger.warn("charset not suport:" + encoding);
            throw new ApiException(ErrorCode.CHARSET_NOT_SUPORT);
        }
        return requestMsg;
    }

    public static String getSignForErp(RequestMsg requestMsg, String token) {

        String signString = buildJsonStrByRequestMsg(requestMsg, token);
        String signDecode = SignUtil.decode(signString);

        return MD5Util.getMd5(signDecode);

    }
}
